{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# tkinter/Tkinter基础\n",
    "### Python 提供了多个图形开发界面的库，几个常用 Python GUI 库如下：\n",
    "* <strong>tkinter/Tkinter：</strong> tkinter/Tkinter 模块是 Python 的标准<strong>轻量级</strong> GUI工具包的接口(框架） .tkinter/Tkinter 可以在大多数的 Unix 平台下使用,同样可以应用在 Windows 和 Macintosh 系统里。Tk8.0 的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中。\n",
    "* <strong>wxPython：</strong>wxPython 是一款开源软件，是 Python 语言的一套优秀的<strong>重量级</strong> GUI 图形库（框架），允许 Python 程序员很方便的创建完整的、功能健全的 GUI 用户界面。\n",
    "* <strong>PyQt：最主流的Python GUI框架，建议作为主攻方向深入学习</strong>\n",
    "## 1. 什么是tkinter/Tkinter\n",
    "Tkinter 是 Python2 的标准 GUI 库。Python2 使用 Tkinter 可以快速的创建 GUI 应用程序。\n",
    "tkinter 是 Python3 的标准 GUI 库。Python3 使用 tkinter 可以快速的创建 GUI 应用程序。\n",
    "\n",
    "由于 tkinter/Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import tkinter/Tkinter 库、而且 IDLE 也是用 tkinter/Tkinter 编写而成、对于简单的图形界面 tkinter/Tkinter 还是能应付自如的。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 2. 使用tkinter编写基础GUI界面：\n",
    "### 2.1 GUI界面3要素：\n",
    "* 创建窗口\n",
    "* 死循环\n",
    "* 处理事件"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "import tkinter\n",
    "\n",
    "def key_event():\n",
    "    pass\n",
    "\n",
    "win = tkinter.Tk()\n",
    "win.bind('<Key>', key_event)\n",
    "win.mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-06T16:59:22.984278Z",
     "end_time": "2023-10-06T16:59:25.251414Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2.2 控制窗口大小位置及标题\n",
    "<h4 style=\"color:RED\">geometry(\"widthxheight+x+y\") 窗口宽：width 高：height 距屏幕左边x,距屏幕顶部y</h4>\n",
    "<h4 style=\"color:RED\">geometry(\"widthxheight-x-y\") 窗口宽：width 高：height 距屏幕右边x,距屏幕底部y</h4>"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "import tkinter\n",
    "\n",
    "def key_event(event):\n",
    "    pass\n",
    "\n",
    "win = tkinter.Tk()\n",
    "win.title(\"HelloWorld\")\n",
    "win.geometry('800x480+400+200')\n",
    "win.bind('<Key>', key_event)\n",
    "win.mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-06T17:22:02.866410Z",
     "end_time": "2023-10-06T17:22:09.489125Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2.3 处理键盘事件"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "import tkinter\n",
    "\n",
    "def key_event(event):\n",
    "    if event.keysym in ['q','Q']:\n",
    "        win.quit() #NoteBook接管了程序退出控制，所以会有问题\n",
    "        # exit()\n",
    "\n",
    "win = tkinter.Tk()\n",
    "win.title(\"HelloWorld\")\n",
    "win.geometry('800x480+400+200')\n",
    "win.bind('<Key>', key_event)\n",
    "win.mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-06T17:22:56.163071Z",
     "end_time": "2023-10-06T17:23:08.487207Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2.4 使用Widget\n",
    "### 2.4.1 使用Button（按钮）Widget:\n",
    "<h4 style=\"color:red\">对于按钮，需要处理的就3件事：</h4>\n",
    "\n",
    "* <h4 style=\"color:red\">按钮的样子 —— widget参数设置</h4>\n",
    "* <h4 style=\"color:red\">按钮放在哪 —— 容器布局</h4>\n",
    "* <h4 style=\"color:red\">点击按钮后做什么 ——widget事件绑定</h4>\n",
    "\n",
    "#### 2.4.1.1 Widget事件的两种绑定方法：\n",
    "* ”command“方法：简单\n",
    "* bind方法：复杂，但可以处理不同的鼠标按键，以及event参数\n",
    "#### 五种鼠标事件：\n",
    "* < Button - 1 > 表示鼠标左键，\n",
    "* < Button - 2 > 表示鼠标中键，\n",
    "* < Button - 3 > 表示鼠标右键，\n",
    "* < Button - 4 > 表示滚轮上滑（Linux）,\n",
    "* < Button - 5 > 表示滚轮下滑（Linux）,"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "outputs": [],
   "source": [
    "import tkinter\n",
    "from tkinter import messagebox #messagebox必须单独import\n",
    "def key_event(event):\n",
    "    if event.keysym in ['q','Q']:\n",
    "        win.quit() # NoteBook接管了程序退出控制，所以会有问题\n",
    "        # exit()\n",
    "def helloCallBack():\n",
    "    messagebox.showinfo(\"标题\",\"天津大学精密仪器与光电子工程学院!\")\n",
    "\n",
    "def leftButtonCallback(e):\n",
    "    print(e)\n",
    "    messagebox.showinfo(\"标题\",\"leftButton Callback\")\n",
    "\n",
    "win = tkinter.Tk()\n",
    "win.title(\"HelloWorld\")\n",
    "win.geometry('800x480+400+200')\n",
    "button1 = tkinter.Button(win, text =\"点我\", height=4,width=20) #如果widget的内容是文本则width,height的单位个字符，如果内容是图片则单位是像素\n",
    "button1[\"command\"] = helloCallBack\n",
    "# button1.bind(helloCallBack)\n",
    "button1.pack()\n",
    "button2 = tkinter.Button(win, text=\"退出\", fg=\"red\", command=win.quit)\n",
    "button2.pack(side='bottom')\n",
    "button3 = tkinter.Button(win)\n",
    "button3[\"text\"] = \"Left Button\"\n",
    "button3.pack(side='left')\n",
    "button3.bind('<Button-3>',leftButtonCallback)\n",
    "win.bind('<Key>', key_event)\n",
    "win.mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-06T21:11:00.647356Z",
     "end_time": "2023-10-06T21:11:05.458718Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### 2.4.1.2 Tkinter布局管理的三种方法\n",
    "\n",
    "<table style=\"text-align: center;\">\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td width=\"200px\">方法</td>\n",
    "    <td width=\"400px\">说明</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td width=\"200px\">pack()</td>\n",
    "    <td width=\"400px\">按照控件的添加顺序其进行排列，遗憾的是此方法灵活性较差</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >grid()</td>\n",
    "    <td >以行和列（网格）形式对控件进行排列，此种方法使用起来较为灵活</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >place()</td>\n",
    "    <td >可以指定组件大小以及摆放位置，三个方法中最为灵活的布局方法</td>\n",
    "  </tr>\n",
    "</table>\n"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### <strong>pack()</strong>\n",
    "###### pack() 是一种较为简单的布局方法，在不使用任何参数的情况下，它会将控件以添加时的先后顺序，自上而下，一行一行的进行排列，并且默认居中显示。pack() 方法的常用参数如下所示：\n",
    "<table style=\"text-align: center;\">\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td width=\"100px\">属性</td>\n",
    "    <td width=\"400px\">说明</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >anchor</td>\n",
    "    <td >组件在窗口中的对齐方式，有 9 个方位参数值，比如\"n\"/\"w\"/\"s\"/\"e\"/\"ne\"，以及 \"center\" 等（这里的 e w s n分别代表，东西南北）</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >expand</td>\n",
    "    <td >是否可扩展窗口，参数值为 True（扩展）或者 False（不扩展），默认为 False，若设置为 True，则控件的位置始终位于窗口的中央位置</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >fill</td>\n",
    "    <td >参数值为 X/Y/BOTH/NONE，表示允许控件在水平/垂直/同时在两个方向上进行拉伸，比如当 fill = X 时，控件会占满水平方向上的所有剩余的空间。</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >ipadx,ipady</td>\n",
    "    <td >需要与 fill 参数值共同使用，表示组件与内容和组件边框的距离（内边距），比如文本内容和组件边框的距离，单位为像素(p)，或者厘米(c)、英寸(i)</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >padx,pady</td>\n",
    "    <td >用于控制组件之间的上下、左右的距离（外边距），单位为像素(p)，或者厘米(c)、英寸(i)</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >side</td>\n",
    "    <td >组件放置在窗口的哪个位置上，参数值 'top','bottom','left','right'。注意，单词小写时需要使用字符串格式，若为大写单词则不必使用字符串格式</td>\n",
    "  </tr>\n",
    "</table>"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [],
   "source": [
    "from tkinter import  *\n",
    "win = Tk()\n",
    "win.title(\"Python程序设计基础\")\n",
    "win.geometry('450x300+300+300')\n",
    "win.iconbitmap('app.ico')\n",
    "lb_red = Label(win,text=\"红色\",bg=\"Red\",fg='#ffffff',relief=GROOVE)\n",
    "# 默认以top方式放置\n",
    "lb_red.pack()\n",
    "lb_blue = Label(win,text=\"蓝色\",bg=\"blue\",fg='#ffffff',relief=GROOVE)\n",
    "# 沿着水平方向填充，使用 pady 控制蓝色标签与其他标签的上下距离为 5 个像素\n",
    "lb_blue.pack(fill=X,pady='5px')\n",
    "lb_green = Label(win,text=\"绿色\",bg=\"green\",fg='#ffffff',relief=RAISED)\n",
    "# 将 黄色标签所在区域都填充为黄色，当使用 fill 参数时，必须设置 expand = 1，否则不能生效\n",
    "lb_green.pack(side=LEFT,expand=1,fill = BOTH)\n",
    "win.mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-07T10:57:19.655714Z",
     "end_time": "2023-10-07T10:57:24.120596Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### <strong>grid()</strong>\n",
    "###### grid() 函数是一种基于网格式的布局管理方法，相当于把窗口看成了一张由行和列组成的表格。当使用该 grid 函数进行布局的时，表格内的每个单元格都可以放置一个控件，从而实现对界面的布局管理。\n",
    "<table style=\"text-align: center;\">\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td width=\"100px\">属性</td>\n",
    "    <td width=\"400px\">说明</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >column</td>\n",
    "    <td >控件位于表格中的第几列，窗体最左边的为起始列，默认为第 0 列</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >expand</td>\n",
    "    <td >控件实例所跨的列数，默认为 1 列，通过该参数可以合并一行中多个领近单元格。</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >ipadx,ipady</td>\n",
    "    <td >用于控制内边距，在单元格内部，左右、上下方向上填充指定大小的空间。</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >padx,pady</td>\n",
    "    <td >用于控制外边距，在单元格外部，左右、上下方向上填充指定大小的空间。</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >row</td>\n",
    "    <td >组件放置在窗口的哪个位置上，参数值 'top','bottom','left','right'。注意，单词小写时需要使用字符串格式，若为大写单词则不必使用字符串格式</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >rowspan</td>\n",
    "    <td >控件实例所跨的行数，默认为 1 行，通过该参数可以合并一列中多个领近单元格。</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >sticky</td>\n",
    "    <td >该属性用来设置控件位于单元格那个方位上，参数值和 anchor 相同，若不设置该参数则控件在单元格内居中</td>\n",
    "  </tr>\n",
    "</table>\n",
    "\n",
    "#### grid() 方法相比 pack() 方法来说要更加灵活，以网格的方式对组件进行布局管理，让整个布局显得非常简洁、优雅。但是，有一点需要大家要特别注意，在一个程序中不能同时使用 pack() 和 grid() 方法，这两个方法只能二选一，否则程序会运行错误。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [],
   "source": [
    "from tkinter import *\n",
    "#主窗口\n",
    "win = Tk()\n",
    "win.config(bg='#87CEEB')\n",
    "win.title(\"Python程序设计基础\")\n",
    "win.geometry('500x350+300+300')\n",
    "win.iconbitmap('app.ico')\n",
    "#在窗口内创建按钮，以表格的形式依次排列\n",
    "for i in range (10):\n",
    "    for j in range (10):\n",
    "        Button(win, text=\" (\" + str(i) + \",\"+ str(j)+ \")\",bg='#D1EEEE').grid(row=i,column=j)\n",
    "# 在第5行第11列添加一个Label标签\n",
    "Label(win,text=\"天津大学\",fg='blue',font=('楷体',14,'bold')).grid(row =4,column=11)\n",
    "#开始窗口的事件循环\n",
    "win. mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-07T11:05:50.228699Z",
     "end_time": "2023-10-07T11:05:55.538958Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "#### 当使用 grid 函数布局的时，其实就是为各个控件指定行号、列号的过程，我们不需要为每个单元格指定大小，因为 grid 会为每个单元格自动设置一个适合的尺寸。\n",
    "\n",
    "#### 下面通过 grid() 布局管理器制作一个简易的登录界面，代码如下所示："
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [],
   "source": [
    "import tkinter as tk\n",
    "from tkinter import messagebox\n",
    "root = tk.Tk()\n",
    "root.title(\"Python程序实际基础\")\n",
    "root.iconbitmap('app.ico')\n",
    "root.resizable(0,0)\n",
    "tk.Label(root, text=\"用户名\").grid(row=0, sticky=\"w\")\n",
    "tk.Label(root, text=\"密码\").grid(row=1, sticky=\"w\")\n",
    "tk.Entry(root).grid(row=0, column=1)\n",
    "tk.Entry(root, show=\"*\").grid(row=1, column=1)\n",
    "# 加载图片LOGO,注意这里是gif格式的图片\n",
    "photo = tk.PhotoImage(file=\"badge2.gif\")\n",
    "tk.Label(root, image=photo).grid(row=0, column=2, rowspan=2, padx='4px', pady='5px')\n",
    "# 编写一个简单的回调函数\n",
    "def login():\n",
    "    messagebox.showinfo('Python程序设计基础')\n",
    "# 使用grid()函数来布局，并控制按钮的显示位置\n",
    "tk.Button(root, text=\"登录\", width=10, command=login).grid(row=3, column=0, columnspan=2,sticky=\"w\", padx=10, pady=5)\n",
    "tk.Button(root, text=\"退出\", width=10, command=root.quit).grid(row=3, column=1, columnspan=2,sticky=\"e\", padx=10, pady=5)\n",
    "# 开启事件主循环\n",
    "root.mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-07T11:15:48.535328Z",
     "end_time": "2023-10-07T11:16:20.033249Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### <strong>place()</strong>\n",
    "###### 与前两种布局方法相比，采用 place() 方法进行布局管理要更加精细化，通过 place() 布局管理器可以直接指定控件在窗体内的绝对位置，或者相对于其他控件定位的相对位置。\n",
    "\n",
    "###### 下面对 place 布局管理器的常用属性做相关介绍：的布局管理。\n",
    "<table style=\"text-align: center;\">\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td width=\"100px\">属性</td>\n",
    "    <td width=\"400px\">说明</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >anchor</td>\n",
    "    <td >定义控件在窗体内的方位，参数值N/NE/E/SE/S/SW/W/NW 或 CENTER，默认值是 NW</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >bordermode</td>\n",
    "    <td >定义控件的坐标是否要考虑边界的宽度，参数值为 OUTSIDE（排除边界） 或 INSIDE（包含边界），默认值 INSIDE。</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >x、y</td>\n",
    "    <td >定义控件在根窗体中水平和垂直方向上的起始绝对位置</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >relx、rely</td>\n",
    "    <td >\n",
    "      <ol>\n",
    "        <li>定义控件相对于根窗口（或其他控件）在水平和垂直方向上的相对位置（即位移比例），取值范围再 0.0~1.0 之间</li>\n",
    "        <li>可设置 in_ 参数项，相对于某个其他控件的位置</li>\n",
    "      </ol>\n",
    "    </td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >height、width</td>\n",
    "    <td >控件自身的高度和宽度（单位为像素）</td>\n",
    "  </tr>\n",
    "  <tr style=\"text-align: center;\">\n",
    "    <td >relheight、relwidth\t</td>\n",
    "    <td >控件高度和宽度相对于根窗体高度和宽度的比例，取值也在 0.0~1.0 之间</td>\n",
    "  </tr>\n",
    "</table>\n",
    "\n",
    "##### 通过上述描述我们知道，relx和rely参数指定的是控件相对于父组件的位置，而relwidth和relheight参数则是指定控件相对于父组件的尺寸大小。\n",
    "##### 注意：这里父组件指的是当前可操作控件的上层组件，比如在没有使用容器控件（frame）的窗体中，控件的父组件就是主窗口本身，在《Tkinter布局管理容器控件》一节会做针对性介绍。\n",
    "##### 上述表格中关于距离位置的参数容易产生“疑惑”，下面通过一组简单的示例来进一步说明："
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [],
   "source": [
    "from tkinter import *\n",
    "#主窗口\n",
    "win = Tk()\n",
    "win.title(\"Python程序设计基础\")\n",
    "win.iconbitmap('app.ico')\n",
    "#创建一个frame窗体对象，用来包裹标签\n",
    "frame = Frame (win, relief=SUNKEN, borderwidth=2, width=450, height=250)\n",
    "# 在水平、垂直方向上填充窗体\n",
    "frame. pack (side=TOP, fill=BOTH, expand=1)\n",
    "# 创建 \"位置1\"\n",
    "Label1 = Label ( frame, text=\"位置1\",bg='blue',fg='white')\n",
    "# 使用 place,设置第一个标签位于距离窗体左上角的位置（40,40）和其大小（width，height）\n",
    "# 注意这里（x,y）位置坐标指的是标签左上角的位置（以NW左上角进行绝对定位，默认为NW）\n",
    "Label1.place (x=40,y=40, width=60, height=30)\n",
    "# 设置标签2\n",
    "Label2 = Label (frame, text=\"位置2\",bg='purple',fg='white')\n",
    "# 以右上角进行绝对值定位，anchor=NE，第二个标签的位置在距离窗体左上角的(180，80)\n",
    "Label2.place(x=180,y=80, anchor=NE, width=60, height=30)\n",
    "# 设置标签3\n",
    "Label3 = Label (frame, text=\"位置3\",bg='green',fg='white')\n",
    "# 设置水平起始位置相对于窗体水平距离的0.6倍，垂直的绝对距离为80，大小为60，30\n",
    "Label3.place(relx=0.6,y=80, width=60, height=30)\n",
    "# 设置标签4\n",
    "Label4 = Label (frame, text=\"位置4\",bg='gray',fg='white')\n",
    "# 设置水平起始位置相对于窗体水平距离的0.01倍，垂直的绝对距离为80，并设置高度为窗体高度比例的0.5倍，宽度为80\n",
    "Label4.place(relx=0.01,y=80,relheight=0.4,width=80)\n",
    "#开始事件循环\n",
    "win. mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-07T11:26:46.235178Z",
     "end_time": "2023-10-07T11:26:55.628527Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "<h4 style=\"color:red\">注意：在一个父组件中 place()方法可以与 grid() 方法混合使用，要与 pack() 进行区别。</h4>"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2.4.2 tkinter常用Widget汇总：\n",
    "![常用Widget汇总](widget1.jpg)\n",
    "![常用Widget汇总](widget2.jpg)\n",
    "### 这些控件(widget)的使用方法请同学们比照Button控件自行学习"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 3. GUI程序的面向对象写法"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hi there, everyone!\n"
     ]
    }
   ],
   "source": [
    "import tkinter as tk\n",
    "\n",
    "class Application(tk.Frame):\n",
    "    def __init__(self, master=None):\n",
    "        super().__init__(master)\n",
    "        self.master = master\n",
    "        self.pack()\n",
    "        self.create_widgets()\n",
    "\n",
    "    def create_widgets(self):\n",
    "        self.hi_there = tk.Button(self)\n",
    "        self.hi_there[\"text\"] = \"Hello World\\n(click me)\"\n",
    "        self.hi_there[\"command\"] = self.say_hi\n",
    "        self.hi_there.pack(side=\"top\")\n",
    "\n",
    "        self.quit = tk.Button(self, text=\"QUIT\", fg=\"red\",\n",
    "                              command=self.master.destroy)\n",
    "        self.quit.pack(side=\"bottom\")\n",
    "\n",
    "    def say_hi(self):\n",
    "        print(\"hi there, everyone!\")\n",
    "\n",
    "root = tk.Tk()\n",
    "app = Application(master=root)\n",
    "app.mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-06T21:42:30.803276Z",
     "end_time": "2023-10-06T21:42:39.833395Z"
    }
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 4. 一个简单案例：数字时钟"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [],
   "source": [
    "from tkinter import *\n",
    "from time import strftime\n",
    "root = Tk()\n",
    "root.geometry('500x350+300+300')\n",
    "root.iconbitmap('app.ico')\n",
    "root.title(\"Python程序设计基础——数字时钟\")\n",
    "# 设置文本标签\n",
    "lb = Label(root, font=(\"微软雅黑\", 50, \"bold\"), bg='#87CEEB', fg=\"#B452CD\")\n",
    "lb.pack(anchor=\"center\", fill=\"both\", expand=1)\n",
    "# 定义一个mode标志\n",
    "mode = 'time'\n",
    "# 定义显示时间的函数\n",
    "def showtime():\n",
    "    if mode == 'time':\n",
    "        #时间格式化处理\n",
    "        string = strftime(\"%H:%M:%S %p\")\n",
    "    else:\n",
    "        string = strftime(\"%Y-%m-%d\")\n",
    "    lb.config(text=string)\n",
    "    # 每隔 1秒钟执行time函数\n",
    "    lb.after(1000, showtime)\n",
    "# 定义鼠标处理事件，点击时间切换为日期样式显示\n",
    "def mouseClick(event):\n",
    "    global mode\n",
    "    if mode == 'time':\n",
    "        # 点击切换mode样式为日期样式\n",
    "        mode = 'date'\n",
    "    else:\n",
    "        mode = 'time'\n",
    "lb.bind(\"<Button>\", mouseClick)\n",
    "# 调用showtime()函数\n",
    "showtime()\n",
    "# 显示窗口\n",
    "mainloop()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-07T11:32:53.368654Z",
     "end_time": "2023-10-07T11:33:07.530880Z"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "start_time": "2023-10-07T11:32:48.511841Z",
     "end_time": "2023-10-07T11:32:48.555844Z"
    }
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
